package drds.binlog.event;

import drds.binlog.LogByteBlock;

import java.io.IOException;

/**
 * Event responsible for LOAD DATA execution, it similar to Query_log_event but
 * before executing the query it substitutes original filename in LOAD DATA
 * query with name of temporary file.
 * <ul>
 * <li>4 bytes. The ID of the file to load.</li>
 * <li>4 bytes. The start index$originIndex within the statement for filename
 * substitution.</li>
 * <li>4 bytes. The end index$originIndex within the statement for filename substitution.
 * </li>
 * <li>1 byte. How to handle duplicates: LOAD_DUP_ERROR = 0, LOAD_DUP_IGNORE =
 * 1, LOAD_DUP_REPLACE = 2</li>
 * </ul>
 */
public final class ExecuteLoadQueryLogEvent extends QueryLogEvent
{

    /*
     * Elements of this enum describe how LOAD DATA handles duplicates.
     */
    public static final int LOAD_DUP_ERROR = 0;
    public static final int LOAD_DUP_IGNORE = LOAD_DUP_ERROR + 1;
    public static final int LOAD_DUP_REPLACE = LOAD_DUP_IGNORE + 1;
    /* ELQ = "Execute Load Query" */
    public static final int ELQ_FILE_ID_OFFSET = QUERY_HEADER_LEN;
    public static final int ELQ_FN_POS_START_OFFSET = ELQ_FILE_ID_OFFSET + 4;
    public static final int ELQ_FN_POS_END_OFFSET = ELQ_FILE_ID_OFFSET + 8;
    public static final int ELQ_DUP_HANDLING_OFFSET = ELQ_FILE_ID_OFFSET + 12;
    /**
     * file_id of temporary file
     */
    private long fileId;
    /**
     * pointer to the part of the query that should be substituted
     */
    private int fnPosStart;
    /**
     * pointer to the end of this part of query
     */
    private int fnPosEnd;
    /**
     * We have to store type of duplicateBasedOnIndex handling explicitly, because for LOAD
     * DATA it also depends on LOCAL option. And this part of query will be
     * rewritten during replication so this information may be lost...
     */
    private int dupHandling;

    public ExecuteLoadQueryLogEvent(LogHeader logHeader, LogByteBlock logByteBlock, FormatDescriptionLogEvent formatDescriptionLogEvent)
            throws IOException
    {
        super(logHeader, logByteBlock, formatDescriptionLogEvent);

        logByteBlock.index(formatDescriptionLogEvent.commonHeaderLength + ELQ_FILE_ID_OFFSET);

        fileId = logByteBlock.getUint32BasedOnIndex(); // ELQ_FILE_ID_OFFSET
        fnPosStart = (int) logByteBlock.getUint32BasedOnIndex(); // ELQ_FN_POS_START_OFFSET
        fnPosEnd = (int) logByteBlock.getUint32BasedOnIndex(); // ELQ_FN_POS_END_OFFSET
        dupHandling = logByteBlock.getInt8BasedOnIndex(); // ELQ_DUP_HANDLING_OFFSET

        final int len = query.length();
        if (fnPosStart > len || fnPosEnd > len || dupHandling > LOAD_DUP_REPLACE)
        {
            throw new IOException(String.format("Invalid ExecuteLoadQueryLogEvent: fn_pos_start=%d, "
                    + "fn_pos_end=%d, dup_handling=%d", fnPosStart, fnPosEnd, dupHandling));
        }
    }

    public final int getFilenamePosStart()
    {
        return fnPosStart;
    }

    public final int getFilenamePosEnd()
    {
        return fnPosEnd;
    }

    public final String getFilename()
    {
        if (query != null) return query.substring(fnPosStart, fnPosEnd).trim();

        return null;
    }

    public final long getFileId()
    {
        return fileId;
    }
}
